package com.maiji.cloud.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.maiji.cloud.entities.login.AreaInfo;
import com.maiji.cloud.entities.login.UserInfo;
import com.maiji.cloud.entities.shopingmall.*;
import com.maiji.cloud.listener.MaijiTask;
import com.maiji.cloud.listener.MyListener;
import com.maiji.cloud.mapper.*;
import com.maiji.cloud.microservice.UserInfoService;
import com.maiji.cloud.microservice.AreaInfoService;
import com.maiji.cloud.request.BaseDataReqDto;
import com.maiji.cloud.request.ReqMetaData;
import com.maiji.cloud.request.shopingmall.*;
import com.maiji.cloud.response.*;
import com.maiji.cloud.response.login.UserInfoResData;
import com.maiji.cloud.response.shopingmall.*;
import com.maiji.cloud.service.*;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.maiji.cloud.utils.*;
import net.sf.json.JSONObject;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jetty.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Transactional
public class ShopingOrderServiceImpl extends ServiceImpl<ShopingOrderMapper, ShopingOrder>
        implements ShopingOrderService {

    private Logger logger = LoggerFactory.getLogger(ShopingOrderServiceImpl.class);
    @Value("${realmName}")
    private String realmName;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private ShopingOrderMapper shopingOrderMapper;
    @Autowired
    private GoodsMapper goodsMapper;
    @Autowired
    private GoodsService goodsService;
    @Autowired
    private ShopingCartService shopingCartService;
    @Autowired
    private ShopingCartMapper shopingCartMapper;
    @Autowired
    private CapitalMainService capitalMainService;
    @Autowired
    private ShopingOrderMiddleShopingCartService somscService;
    @Autowired
    private ShopingAddressService shopingAddressService;
    @Autowired
    private UserInfoService appUserService;
    @Autowired
    private ShipmentsInfoMapper shipmentsInfoMapper;
    @Autowired
    private ShipmentsInfoService shipmentsInfoService;
    @Autowired
    private CouponsService couponsService;
    @Autowired
    private ExchangeLogService exchangeLogService;
    @Autowired
	private ExchangeLogMapper exchangeLogMapper;
    @Autowired
    private AreaInfoService areaInfoService;
    @Autowired
    private MaijiTask maijiTask;
    @Autowired
    private ShopingOrderRefundService shopingOrderRefundService;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private ShopingOrderEditLogService shopingOrderEditLogService;
    @Autowired
	private CapitalMainMapper capitalMainMapper;
    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public BaseResDto orderConfirmReceived(String orderId) {
        ShopingOrder shopingOrder = new ShopingOrder()
                .setUuId(orderId)
                .setStatus(3)
                .setReceiveDate(new Date());
        if (! updateById(shopingOrder)) return new BaseResDto(Status.ERROR);
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    public BaseResDto editOrder(ShopingOrderEditLogReqData data) {
        ShopingOrder shopingOrder = new ShopingOrder()
                .setUuId(data.getOrderId()).setAmount(data.getAmountNew())
                .setSellerRemarks(data.getSellerRemarks()).setDeliveryFee(data.getDeliveryFeeNew());
        if (! updateById(shopingOrder)) return new BaseResDto(Status.ERROR);
        if (! shopingOrderEditLogService.save(data)) return new BaseResDto(Status.ERROR);
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    public BaseDataResDto<ShopingOrderResData> initOrder(OrderInitReqDto.OrderInitReqData data, String userId, String token) {
        ShopingOrderResData shopingOrderResData = new ShopingOrderResData();
        Double presentPayable = 0.00;
        Integer weightTotal = 0;
        List<ShopingCartResData> shopingCartResDataList = Lists.newArrayList();

        // 初始化购物车订单
        List<String> shopingCartIds = data.getShopingCartIds();
        if (shopingCartIds != null && shopingCartIds.size() != 0) {
            List<ShopingCart> shopingCartList = shopingCartService.selectBatchIds(shopingCartIds);
            List<String> goodsIds = shopingCartList.parallelStream().map(ShopingCart::getGoodsId).collect(Collectors.toList());
            List<Goods> goodsList = goodsService.selectBatchIds(goodsIds);
            Map<String, Goods> goodsMap = goodsList.parallelStream().collect(Collectors.toMap(Goods::getUuId, goods -> goods));
            if (shopingCartList.parallelStream().anyMatch(sc -> goodsMap.get(sc.getGoodsId()).getUpDown() == 2
                    && sc.getPurchaseQuantity() > goodsMap.get(sc.getGoodsId()).getStockVolume()))
                return new BaseDataResDto(Status.ERROR.setMessage("购买的商品库存不足"));
            presentPayable = shopingCartList.parallelStream()
                    .map(ShopingCart::getPresentPayable)
                    .reduce(Double.valueOf(0), (pp1, pp2) -> Arith.add(2, pp1, pp2));
            weightTotal = shopingCartList.parallelStream()
                    .map(ShopingCart::getWeightTotal)
                    .reduce(Integer.valueOf(0), Integer::sum);
            shopingCartResDataList = shopingCartList.parallelStream()
                    .map(shopingCart -> {
                        ShopingCartResData shopingCartResData = new ShopingCartResData();
                        BeanUtils.copyProperties(shopingCart, shopingCartResData);
                        GoodsResData goodsById = goodsService.findGoodsById(shopingCart.getGoodsId());
                        return shopingCartResData.setGoods(goodsById);
                    }).collect(Collectors.toList());
        }

        // 初始化单品订单
        String goodsId = data.getGoodsId();
        Integer purchaseQuantity = data.getPurchaseQuantity();
        String shopingCartId = UUID_MD5.getUUID();
        if (StringUtil.isNotBlank(goodsId) && purchaseQuantity != null && purchaseQuantity.intValue() != 0) {
            GoodsResData goods = goodsService.findGoodsById(goodsId);
            if (goods.getUpDown() == 2 || purchaseQuantity > goods.getStockVolume())
                return new BaseDataResDto(Status.USER_WORNING_INFO.setMessage("购买的商品库存不足"));
            ShopingCart shopingCart = new ShopingCart();
            Double originalPayable = Arith.multiplys(2, goods.getOriginalPrice(), purchaseQuantity);
            presentPayable = Arith.multiplys(2, goods.getPresentPrice(), purchaseQuantity);
            weightTotal = goods.getWeight() * purchaseQuantity;
            shopingCart.setUuId(shopingCartId).setUserId(userId).setGoodsId(goods.getUuId())
                    .setPresentPayable(presentPayable).setWeightTotal(weightTotal).setUpdateDate(new Date())
                    .setPurchaseQuantity(purchaseQuantity).setOriginalPayable(originalPayable).setAddAuto(true);
            // 保存购买商品信息
            if (! shopingCartService.insert(shopingCart)) {
                logger.info("初始化单品订单UserID={} ===>> 保存购买商品信息 ===>> 失败", userId);
                return new BaseDataResDto(Status.ERROR);
            } else {
                ShopingCartResData shopingCartResData = new ShopingCartResData();
                BeanUtils.copyProperties(shopingCart, shopingCartResData);
                shopingCartResDataList.add(shopingCartResData.setGoods(goods));
            }
        }
        shopingOrderResData.setShopingCarts(shopingCartResDataList).setScAmount(presentPayable);

        // 计算快递费
        shopingAddressService.calculateFreight(shopingOrderResData, null, null, userId, presentPayable, weightTotal,false);

        // 计算用户优惠信息
        CapitalMainResData capitalMainResData = capitalMainService.calculateCapitalMain(userId, presentPayable, token);
        Optional<GetDiscountCouponListResData> optional = capitalMainResData.getCouponList().parallelStream()
                .filter(coupon -> StringUtil.isNotBlank(coupon.getExchangeId()) && coupon.getIsUse() == 0).findFirst();
        if (optional.isPresent()) {
            GetDiscountCouponListResData couponResData = optional.get();
            shopingOrderResData.setExchangeId(couponResData.getExchangeId());
            Double coupon = couponResData.getFaceValue().doubleValue();
            shopingOrderResData.setCoupon(coupon);
            Double amount = Arith.subtract(2, shopingOrderResData.getAmount(), coupon);
            shopingOrderResData.setAmount(amount);
        }
        shopingOrderResData.setCapitalMainResData(capitalMainResData);

        return new BaseDataResDto<ShopingOrderResData>(Status.SUCCESS).setData(shopingOrderResData);
    }

    @Override
    public BaseDataResDto<ShopingOrderResData> refreshOrder(OrderRefreshReqDto.OrderRefreshReqData data, String userId, String token) {
        ShopingOrderResData shopingOrderResData = new ShopingOrderResData();
        List<String> shopingCartIds = data.getShopingCartIds();
        Integer purchaseQuantity = data.getPurchaseQuantity();
        if (shopingCartIds.size() == 1 && purchaseQuantity != null) { // 刷新单品购买订单
            if (purchaseQuantity <= 0) return new BaseDataResDto<>(Status.ERROR);
            BaseResDto result = shopingCartService.updateShopingCartQuantity(shopingCartIds.get(0), data.getPurchaseQuantity());
            if (result.getStatus() != Status.SUCCESS) return new BaseDataResDto<>(Status.ERROR);
        }
        List<ShopingCart> shopingCartList = shopingCartService.selectBatchIds(shopingCartIds);
        List<String> goodsIds = shopingCartList.parallelStream().map(ShopingCart::getGoodsId).collect(Collectors.toList());
        List<Goods> goodsList = goodsService.selectBatchIds(goodsIds);
        Map<String, Goods> goodsMap = goodsList.parallelStream().collect(Collectors.toMap(Goods::getUuId, goods -> goods));
        if (shopingCartList.parallelStream().anyMatch(sc -> goodsMap.get(sc.getGoodsId()).getUpDown() == 2
                && sc.getPurchaseQuantity() > goodsMap.get(sc.getGoodsId()).getStockVolume()))
            return new BaseDataResDto(Status.ERROR.setMessage("购买的商品库存不足"));
        Double presentPayable = shopingCartList.parallelStream()
                .map(ShopingCart::getPresentPayable)
                .reduce(Double.valueOf(0), (pp1, pp2) -> Arith.add(2, pp1, pp2));
        Integer weight = shopingCartList.parallelStream()
                .map(ShopingCart::getWeightTotal)
                .reduce(Integer.valueOf(0), Integer::sum);
        List<ShopingCartResData> shopingCartResDataList = shopingCartList.parallelStream().map(shopingCart -> {
            ShopingCartResData shopingCartResData = new ShopingCartResData();
            BeanUtils.copyProperties(shopingCart, shopingCartResData);
            shopingCartResData.setGoods(goodsService.findGoodsById(shopingCart.getGoodsId()));
            return shopingCartResData;
        }).collect(Collectors.toList());
        shopingOrderResData.setShopingCarts(shopingCartResDataList)
                .setScAmount(presentPayable);

        // 计算快递费
        shopingAddressService.calculateFreight(shopingOrderResData, data.getShopingAddressId(), data.getDeliveryId(), userId, presentPayable, weight,false);
        Double amount = shopingOrderResData.getAmount();

        // 计算用户优惠信息
        CapitalMainResData cmd = capitalMainService.calculateCapitalMain(userId, presentPayable, token);
        shopingOrderResData.setCapitalMainResData(cmd);
        if (BooleanUtils.isTrue(data.getFundUsable()) && cmd.getFundUsable()) {  // 使用减肥基金
            Double fund = cmd.getFund();
            amount = Arith.subtract(2, amount, fund);
            shopingOrderResData.setFund(fund);
        }
        if (BooleanUtils.isTrue(data.getIntegralUsable()) && cmd.getIntegralUsable()) { // 使用积分兑现
            Double integralMoney = cmd.getIntegralMoney();
            amount = Arith.subtract(2, amount, integralMoney);
            shopingOrderResData.setIntegralMoney(integralMoney)
                    .setIntegral(cmd.getIntegral());
        }
        GetDiscountCouponListResData coupon = null;
        String exchangeId = data.getExchangeId();
        if (BooleanUtils.isNotFalse(data.getCouponUsable()) || StringUtil.isNotBlank(exchangeId)) {
            if (StringUtil.isNotBlank(exchangeId)) // 用户选择使用的优惠券
                coupon = couponsService.checkCouponUseable(presentPayable, exchangeId, token);
            if (StringUtil.isBlank(exchangeId) || coupon == null) {  // 默认选择使用可用优惠券
                Optional<GetDiscountCouponListResData> optional = cmd.getCouponList().parallelStream()
                        .filter(c -> StringUtil.isNotBlank(c.getExchangeId()) && c.getIsUse() == 0).findFirst();
                if (optional.isPresent()) {
                    coupon = optional.get();
                    exchangeId = coupon.getExchangeId();
                }
            }
        }
        if (coupon != null) {
            Double faceValue = Double.valueOf(coupon.getFaceValue().toString());
            amount = Arith.subtract(2, amount, faceValue);
            shopingOrderResData.setExchangeId(exchangeId).setCoupon(faceValue);
        } else shopingOrderResData.setExchangeId(null).setCoupon(null);

        // 判断用户余额是否可用
        cmd.setMoneyUsable(cmd.getMoney() >= amount);
        shopingOrderResData.setAmount(amount);

        return new BaseDataResDto<ShopingOrderResData>(Status.SUCCESS).setData(shopingOrderResData);
    }

    @Override
    public BaseDataResDto<ShopingOrderResData> orderSubmit(OrderSubmitReqDto.OrderSubmitReqData data, String userId, String token) {
        if (! redisTemplate.opsForValue().setIfAbsent("orderSubmit:" + userId, 123))
            return new BaseDataResDto<>(Status.ERROR.setMessage("不可重复提交订单"));
        redisTemplate.expire("orderSubmit:" + userId, 10, TimeUnit.SECONDS);
        ShopingOrderResData shopingOrderResData = new ShopingOrderResData();
        Double fund = null;
        Integer integral = null;
        Double integralMoney = null;
        String exchangeId = data.getExchangeId();
        Double couponFaceValue = null;

        // 验证提交订单应付款是否正确：提交购物车订单
        List<String> shopingCartIds = data.getShopingCartIds();
        if (shopingCartIds == null || shopingCartIds.size() == 0)
            return new BaseDataResDto<>(Status.PARAMETERERROR.setMessage("购物信息不可为空"));
        Integer weightTotal = shopingCartService.orderSubmitCalculate(shopingOrderResData, shopingCartIds);
        if (weightTotal == 0) return new BaseDataResDto(Status.USER_WORNING_INFO.setMessage("购买的商品库存不足"));

        // 计算快递费
        String shopingAddressId = data.getShopingAddressId();
        if (StringUtil.isBlank(shopingAddressId)) return new BaseDataResDto<>(Status.PARAMETERERROR.setMessage("收货地址不可为空"));
        shopingAddressService.calculateFreight(shopingOrderResData, shopingAddressId, data.getDeliveryId(), userId, shopingOrderResData.getScAmount(), weightTotal,true);

        CapitalMainResData cmd = capitalMainService.calculateCapitalMain(userId, shopingOrderResData.getScAmount(), token);
        Double discount = Double.valueOf(0);
        if (BooleanUtils.isTrue(data.getFundUsable()) && cmd.getFundUsable()) {  // 使用减肥基金
            fund = cmd.getFund();
            discount = Arith.add(2, discount, fund);
        }
        if (BooleanUtils.isTrue(data.getIntegralUsable()) && cmd.getIntegralUsable()) { // 使用积分兑现
            integral = cmd.getIntegral();
            integralMoney = cmd.getIntegralMoney();
            discount = Arith.add(2, discount, integralMoney);
            shopingOrderResData.setIntegral(integral)
                    .setIntegralMoney(integralMoney);
        }
        if (exchangeId != null) {
            GetDiscountCouponListResData coupon = couponsService.checkCouponUseable(shopingOrderResData.getScAmount(), exchangeId, token);
            if (coupon == null) return new BaseDataResDto<>(Status.ERROR.setMessage("优惠券不可用"));
            couponFaceValue = Double.valueOf(coupon.getFaceValue().toString());
            discount = Arith.add(2, discount, couponFaceValue);
            shopingOrderResData.setExchangeId(exchangeId)
                    .setCoupon(couponFaceValue);
        }
        Double amount = Arith.subtract(2, shopingOrderResData.getAmount(), discount);
        logger.info("提交订单UserID={} ===>> 应付款{} == 商品总价{}元 - 折扣{}元 + 运费{}元",
                new Object[]{userId, amount, shopingOrderResData.getScAmount(), discount, shopingOrderResData.getDeliveryFee()});

        // 保存订单信息
        ShopingOrder order = new ShopingOrder();
        BeanUtils.copyProperties(data, order);
        String orderId = UUID_MD5.getUUID();
        String orderNo = UUID_MD5.orderNo();
        order.setUuId(orderId).setPrinted(false).setUserId(userId).setAmount(amount).setRemindSend(false)
                .setDeliveryFee(shopingOrderResData.getDeliveryFee()).setShopingAddressId(shopingOrderResData.getShopingAddressId())
                .setOrderNo(orderNo).setCreateDate(new Date()).setWeightTotal(weightTotal).setDelivery(shopingOrderResData.getDelivery());
        if (fund != null) order.setFund(fund);
        if (integral != null) order.setIntegral(integral);
        if (integralMoney != null) order.setIntegralMoney(integralMoney);
        if (couponFaceValue != null) order.setCoupon(couponFaceValue);
        if (BooleanUtils.isNotFalse(data.getCouponUsable()) && StringUtil.isNotBlank(exchangeId)) order.setExchangeId(exchangeId);
        if (! insert(order)) return new BaseDataResDto(Status.ERROR);
        logger.info("提交订单UserID={} ===>> 保存订单信息 ===>> 成功", userId);

        // 保存购物商品和订单表的关联关系
        if (! somscService.orderSubmitSave(orderId, shopingCartIds)) return new BaseDataResDto(Status.ERROR);
        logger.info("提交订单OrderID={} ===>> 保存购物商品和订单表的关联关系 ===>> 成功", orderId);

        if (integral != null)   // 冻结订单中使用的积分
            if (! capitalMainService.updateCapitalMain(userId, FlowTypeEnum.INTEGRAL, integral.toString(),
                    FlowTypeEnum.DECREASE, FlowTypeEnum.ORDER_SUBMIT, orderId)) {
                logger.info("提交订单OrderID={} ===>> 冻结订单中使用的积分 ===>> 失败", orderId);
                return new BaseDataResDto(Status.ERROR.setMessage("冻结订单中使用的积分"));
            }
        if (fund != null)   // 冻结订单中使用的基金
            if (! capitalMainService.updateCapitalMain(userId, FlowTypeEnum.FUND, fund.toString(),
                    FlowTypeEnum.DECREASE, FlowTypeEnum.ORDER_SUBMIT, orderId)) {
                logger.info("提交订单OrderID={} ===>> 冻结订单中使用的基金 ===>> 失败", orderId);
                return new BaseDataResDto(Status.ERROR.setMessage("冻结订单中使用的基金"));
            }
        if (StringUtil.isNotBlank(exchangeId))
            if (! exchangeLogService.updateById(new ExchangeLog().setUuId(exchangeId).setIsUse(1))) {
                logger.info("提交订单OrderID={} ===>> 冻结订单中使用的优惠券 ===>> 失败", orderId);
                return new BaseDataResDto(Status.ERROR.setMessage("冻结订单中使用的优惠券"));
            }

        // 定时取消订单
        MyListener.AUTOCANCELORDERTIMER.schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    maijiTask.TimingCancelOrderTask(orderId, MyListener.AUTOCANCELORDERMINUTES);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, TimeUnit.MINUTES.toMillis(MyListener.AUTOCANCELORDERMINUTES));

        BeanUtils.copyProperties(order, shopingOrderResData);

        Integer wt = shopingCartService.orderSubmitCalculate(null, shopingCartIds);
        if (wt == 0) return new BaseDataResDto(Status.ERROR.setMessage("购买的商品库存不足"));
        return new BaseDataResDto<ShopingOrderResData>(Status.SUCCESS).setData(shopingOrderResData.setRealmName(realmName));
    }

    @Override
    public BaseDataResDto<ShopingOrderResData> findOrderById(String orderId) {
        ShopingOrder shopingOrder = selectById(orderId);
        ShopingOrderResData shopingOrderResData = new ShopingOrderResData()
                .setUser(userInfoService.findUserInfoResDataByUserId(shopingOrder.getUserId()))
                .setShopingCarts(somscService.findShopingCartResDataListByOrderId(orderId))
                .setShopingAddress(shopingAddressService.findShopingAddressResDataById(shopingOrder.getShopingAddressId()));
        if (shopingOrder.getRefundStatus() > -1) shopingOrderResData.setRefundData(shopingOrderRefundService.findResDataByOrderId(orderId));
        BeanUtils.copyProperties(shopingOrder, shopingOrderResData);
        Double scAmount = shopingOrderResData.getShopingCarts().parallelStream()
                .map(ShopingCartResData::getPresentPayable).reduce(0.00, (pp1, pp2) -> Arith.add(2, pp1, pp2));
        return new BaseDataResDto(Status.SUCCESS).setData(shopingOrderResData.setScAmount(scAmount));
    }

    @Override
    public BaseDataResDto<ShopingOrderResData>  cancelOrderById(String orderId, String cancelReason) {
        ShopingOrder shopingOrder = selectById(orderId);
        if (shopingOrder == null || shopingOrder.getStatus() != 0) return new BaseDataResDto<>(Status.ERROR);
        shopingOrder.setStatus(4).setCancelDate(new Date()).setCancelReason(cancelReason);
        if (! updateById(shopingOrder)) return new BaseDataResDto(Status.ERROR);
        String userId = shopingOrder.getUserId();
        Double fund = shopingOrder.getFund();
        if (fund != null) capitalMainService.updateCapitalMain(userId, FlowTypeEnum.FUND, fund.toString(),
                FlowTypeEnum.INCREASE, FlowTypeEnum.ORDER_CANCEL, orderId);
        Integer integral = shopingOrder.getIntegral();
        if (integral != null) capitalMainService.updateCapitalMain(userId, FlowTypeEnum.INTEGRAL, integral.toString(),
                FlowTypeEnum.INCREASE, FlowTypeEnum.ORDER_REFUND_INTEGRAL, orderId);
        String exchangeId = shopingOrder.getExchangeId();
        if (StringUtil.isNotBlank(exchangeId)) exchangeLogService.updateById(new ExchangeLog().setUuId(exchangeId).setIsUse(0));
        ShopingOrderResData shopingOrderResData = new ShopingOrderResData();
        BeanUtils.copyProperties(shopingOrder, shopingOrderResData);
        return new BaseDataResDto<ShopingOrderResData>(Status.SUCCESS).setData(shopingOrderResData);
    }

    @Override
    public BaseResDto delOrdersByIds(List<String> orderIds) {
        if (! deleteBatchIds(orderIds)) return new BaseResDto(Status.ERROR);
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    public BaseResDto remindSendByOrderId(String orderId) {
        if (! updateById(new ShopingOrder().setUuId(orderId).setRemindSend(true)))
            return new BaseResDto(Status.ERROR);
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    public BaseDataResDto<List<ShopingOrderStatusCountResData>> findAllShopingOrderStatusCount(String userId) {
        List<ShopingOrderStatusCountResData> orders = shopingOrderMapper.findAllShopingOrderStatusCount(false, userId);
        orders.addAll(Arrays.asList(0, 1, 2, 3, 4, 5, 6).parallelStream().filter(s1 -> ! orders.parallelStream().anyMatch(sosc -> sosc.getStatus() == s1))
                        .map(s2 -> new ShopingOrderStatusCountResData().setStatus(s2).setCount(0)).collect(Collectors.toList()));
        List<ShopingOrderStatusCountResData> refundOrders = shopingOrderMapper.findAllShopingOrderStatusCount(true, userId);
        if (refundOrders.size() > 0) orders.addAll(refundOrders);
        return new BaseDataResDto<List<ShopingOrderStatusCountResData>>(Status.SUCCESS).setData(orders);
    }

    @Override
    public BaseMetaResDto<List<List<ShopingOrderResData>>> findAllOrders1(OrderFindAllReqData data, ReqMetaData metaData) {
        List<List<ShipmentsInfoEntity>> infoListList = Lists.newArrayList();
        String orderNo = data.getOrderNo();
        if (StringUtil.isNotBlank(orderNo)) {
            ShipmentsInfoEntity shipmentsInfo = shipmentsInfoService.selectOne(new EntityWrapper<ShipmentsInfoEntity>().eq("order_no", orderNo));
            if (shipmentsInfo != null) {
                List<String> orderIds = shipmentsInfoService.selectList(new EntityWrapper<ShipmentsInfoEntity>().eq("express_no", shipmentsInfo.getExpressNo()))
                        .parallelStream().map(ShipmentsInfoEntity::getOrderId).collect(Collectors.toList());
                infoListList = new ArrayList<>(shipmentsInfoService.selectList(new EntityWrapper<ShipmentsInfoEntity>().in("order_id", orderIds))
                        .parallelStream().collect(Collectors.groupingBy(ShipmentsInfoEntity::getExpressNo)).values());
                data.setOrderNo(null).setOrderIds(orderIds);
            }
        }
        BaseMetaResDto<List<ShopingOrderResData>> baseMetaResDto = findAllOrders(data, metaData, null);
        List<ShopingOrderResData> orderResDataList = baseMetaResDto.getData();
        List<List<ShipmentsInfoEntity>> finalInfoListList = infoListList;
        Map<String, List<ShopingOrderResData>> orderListMap = orderResDataList.parallelStream().collect(Collectors.groupingBy(order -> {
            if (finalInfoListList.size() > 0) order.setInfoListList(finalInfoListList);
            ShopingAddressResData sa = order.getShopingAddress();
            AreaInfo areaInfo = sa.getAreaInfo();
            return order.getUserId() + order.getDelivery() + sa.getConsignee() + sa.getTel() + areaInfo.getProvince() + areaInfo.getCity() + areaInfo.getAddress();
        }));
        List<List<ShopingOrderResData>> ordersList = new ArrayList<>(orderListMap.values());
        return new BaseMetaResDto<List<List<ShopingOrderResData>>>(Status.SUCCESS).setData(ordersList);
    }

    @Override
    public BaseMetaResDto<List<ShopingOrderResData>> findOrdersByUserId(String goodsName, String userId) {
        if (StringUtil.isBlank(goodsName)) return new BaseMetaResDto<>(Status.SUCCESS);
        List<String> goodsIds = goodsService.selectList(new EntityWrapper<Goods>().like("name", goodsName))
                .parallelStream().map(Goods::getUuId).collect(Collectors.toList());
        if (goodsIds.size() == 0) return new BaseMetaResDto<>(Status.SUCCESS);
        List<String> scIds = shopingCartService.selectList(new EntityWrapper<ShopingCart>().eq("user_id", userId)
                .in("goods_id", goodsIds)).parallelStream().map(ShopingCart::getUuId).collect(Collectors.toList());
        if (scIds.size() == 0) return new BaseMetaResDto<>(Status.SUCCESS);
        List<String> orderIds = somscService.selectList(new EntityWrapper<ShopingOrderMiddleShopingCart>().in("shoping_cart_id", scIds))
                .parallelStream().map(ShopingOrderMiddleShopingCart::getOrderId).collect(Collectors.toList());
        if (orderIds.size() == 0) return new BaseMetaResDto<>(Status.SUCCESS);
        OrderFindAllReqData orderFindAllReqData = new OrderFindAllReqData().setOrderIds(orderIds);
        return findAllOrders(orderFindAllReqData, new ReqMetaData(1, 9999), userId);
    }

    @Override
    public BaseMetaResDto<List<ShopingOrderResData>> findAllOrders(OrderFindAllReqData data, ReqMetaData metaData, String userId) {
        EntityWrapper<ShopingOrder> entityWrapper = new EntityWrapper<>();
        if (StringUtil.isNotBlank(userId)) entityWrapper.eq("user_id", userId);
        if (StringUtil.isNotBlank(data.getNickName())) {
            HashMap<String, Object> map = Maps.newHashMap();
            map.put("nickName", data.getNickName());
            List<String> userIds = appUserService.selectList(map).parallelStream().map(UserInfo::getUserId).collect(Collectors.toList());
            if (userIds.size() > 0) entityWrapper.in("user_id", userIds);
            else return new BaseMetaResDto<>(Status.USER_NOT_EXIST);
        }
        if (StringUtil.isNotBlank(data.getTel())) {
            List<String> asIds = shopingAddressService.selectList(new EntityWrapper<ShopingAddress>().like("tel", data.getTel()))
                    .parallelStream().map(ShopingAddress::getUuId).collect(Collectors.toList());
            if (asIds.size() == 0) asIds.add("123xyz");
            entityWrapper.in("shoping_address_id", asIds);
        }
        if (StringUtil.isNotBlank(data.getExpressNo())) {
            List<String> infoIds = shipmentsInfoService.selectList(new EntityWrapper<ShipmentsInfoEntity>().eq("express_no", data.getExpressNo()))
                    .parallelStream().map(ShipmentsInfoEntity::getOrderId).collect(Collectors.toList());
            if (infoIds.size() == 0) infoIds.add("123xyz");
            data.setOrderIds(infoIds);
        }
        if (StringUtil.isNotBlank(data.getOrderNo())) entityWrapper.like("order_no", data.getOrderNo());
        if (data.getOrderIds() != null && data.getOrderIds().size() > 0) entityWrapper.in("uu_id", data.getOrderIds());
        if (data.getOrderNos() != null && data.getOrderNos().size() > 0) entityWrapper.in("order_no", data.getOrderNos());
        if (data.getStatus() != null && data.getStatus() != -1 && data.getStatus() != 7) entityWrapper.eq("status", data.getStatus());
        if (BooleanUtils.isTrue(data.getPrinted() != null)) entityWrapper.eq("printed", data.getPrinted());
        if (data.getDelivery() != null) entityWrapper.like("delivery", data.getDelivery());
        if (data.getPayType() != null) entityWrapper.eq("pay_type", data.getPayType());
        if (data.getRefundStatuses() != null && data.getRefundStatuses().size() > 0)
            entityWrapper.in("refund_status", data.getRefundStatuses());
        BaseService.dealWithEntityWrapper(entityWrapper, data.getDeliveryFees(), "delivery_fee");
        BaseService.dealWithEntityWrapper(entityWrapper, data.getAmounts(), "amount");
        BaseService.dealWithEntityWrapper(entityWrapper, data.getFunds(), "fund");
        BaseService.dealWithEntityWrapper(entityWrapper, data.getIntegralMoneys(), "integral_money");
        BaseService.dealWithEntityWrapper(entityWrapper, data.getCoupons(), "coupon");
        BaseService.dealWithEntityWrapper(entityWrapper, data.getCreateDates(), "create_date");
        BaseService.dealWithEntityWrapper(entityWrapper, data.getPayDates(), "pay_date");
        BaseService.dealWithEntityWrapper(entityWrapper, data.getSendDates(), "send_date");
        BaseService.dealWithEntityWrapper(entityWrapper, data.getReceiveDates(), "receive_date");
        BaseService.dealWithEntityWrapper(entityWrapper, data.getCancelDates(), "cancel_date");
        entityWrapper.orderBy(data.getOrderBy(), data.getOrderType().equals("asc")? true: false);
        Page<ShopingOrder> page = selectPage(new Page<>(metaData.getPage(), metaData.getSize()), entityWrapper);
        List<ShopingOrder> shopingOrders = page.getRecords();
        if (shopingOrders.size() == 0) return new BaseMetaResDto<List<ShopingOrderResData>>(Status.SUCCESS).setData(Lists.newArrayList());
        Map<String, String> siMap = Maps.newHashMap();
        if (StringUtil.isBlank(userId)) {
            List<String> orderIds = shopingOrders.parallelStream().filter(order -> order.getStatus() > 1).map(ShopingOrder::getUuId).collect(Collectors.toList());
            if (orderIds.size() > 0) {
                EntityWrapper<ShipmentsInfoEntity> wrapper = new EntityWrapper<>();
                wrapper.in("order_id", orderIds);
                wrapper.setSqlSelect("order_id orderId", "express_no expressNo");
                siMap = shipmentsInfoService.selectList(wrapper).parallelStream().collect(Collectors.groupingBy(ShipmentsInfoEntity::getOrderId,
                        Collectors.mapping(ShipmentsInfoEntity::getExpressNo, Collectors.joining("；"))));
            }
        }
        Map<String, String> finalSiMap = siMap;
        List<ShopingOrderResData> shopingOrderResDataList = findAllShopingOrderResDataList(shopingOrders).parallelStream().map(shopingOrder -> {
            // 订单状态：0-待付款, 1-待发货，2-待收货，3-已收货/待评价，4-已取消，5-已评价，6-订单完成
            Integer status = shopingOrder.getStatus();
            if (status > 1) shopingOrder.setExpressNos(finalSiMap.get(shopingOrder.getUuId()));
            if (status == 1 || status == 2) return shopingOrder.setRefundable(true);
            if (status == 0 || status == 4 ||status == 5 || status == 6) return shopingOrder.setRefundable(false);
            LocalDate receiveDate = shopingOrder.getReceiveDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            LocalDate canRefundDate = receiveDate.plusDays(7);
            if (LocalDate.now().isBefore(canRefundDate)) return shopingOrder.setRefundable(true);
            else return shopingOrder.setRefundable(false);
        }).collect(Collectors.toList());
        ResMetaData resMetaData = new ResMetaData(page.getCurrent(), page.getSize(), page.getTotal());
        return new BaseMetaResDto<List<ShopingOrderResData>>(Status.SUCCESS).setData(shopingOrderResDataList).setResMetaData(resMetaData);
    }

    @Override
    public List<ShopingOrderResData> findAllShopingOrderResDataList (List<ShopingOrder> shopingOrders) {
        // 查询订单用户信息
        List<ShopingOrderResData> shopingOrderResDataList = BaseService.findOneToOne(shopingOrders, "getUserId", ShopingOrderResData.class,
                "setUser", appUserService, "userIds", "getUserId", UserInfoResData.class);
        // 查询订单收货地址信息
        List<String> saIds = shopingOrders.parallelStream().map(ShopingOrder::getShopingAddressId).collect(Collectors.toList());
        List<ShopingAddress> shopingAddresses = shopingAddressService.selectBatchIds(saIds);
        List<ShopingAddressResData> shopingAddressResDataList = BaseService.findOneToOne(shopingAddresses, "getAreaInfoId",
                ShopingAddressResData.class, "setAreaInfo", areaInfoService, "areaInfoIds", "getUuId", AreaInfo.class);
        shopingOrderResDataList = BaseService.dealWithOneToOne(shopingOrderResDataList, "getShopingAddressId", ShopingOrderResData.class,
                "setShopingAddress", shopingAddressResDataList, "getUuId", ShopingAddressResData.class);
        // 查询订单购物车记录信息
        Map<String, List<?>> midMap = BaseService.findOneMidMany(shopingOrderResDataList, "getUuId",
                somscService, "order_id", "getShopingCartId");
        List<ShopingCart> shopingCartList = shopingCartService.selectBatchIds((List<String>) midMap.get("subKeys"));
        List<ShopingCartResData> shopingCartResDataList = shopingCartService.findAllResData(shopingCartList);
        shopingOrderResDataList = BaseService.dealWithOneMidMany(shopingOrderResDataList, "getUuId",
                ShopingOrderResData.class, "setShopingCarts", midMap.get("midList"), "getOrderId",
                "getShopingCartId", shopingCartResDataList, "getUuId", ShopingCartResData.class);
	    return shopingOrderResDataList;
    }

    @Override
	public BaseDataResDto<List<String>> getTrackingNumberByOrderId(BaseDataReqDto<String> param) {
		String orderId = param.getData();
		if (StringUtils.isBlank(orderId))
			new BaseDataResDto<List<String>>(Status.SUCCESS, "订单id为空");
		List<String> list = shipmentsInfoMapper.getExpressNoListByOrderId(orderId);
		BaseDataResDto<List<String>> response = new BaseDataResDto<List<String>>(Status.SUCCESS);
		response.setData(list);
		return response;
	}

	@Override
	public BaseDataResDto<LogisticsInfoResData> getLogisticsInfoByExpressNo(BaseDataReqDto<String> param) throws Exception {
		// 物流单号
		String expressNo = param.getData();
		if (StringUtils.isBlank(expressNo))new BaseDataResDto<List<String>>(Status.SUCCESS, "物流单号为空");
		
		EntityWrapper<ShipmentsInfoEntity> shipmentsInfoEntityWrapper = new EntityWrapper<ShipmentsInfoEntity>();
		shipmentsInfoEntityWrapper.eq("express_no", expressNo);
		ShipmentsInfoEntity shipmentsInfoEntity = shipmentsInfoService.selectOne(shipmentsInfoEntityWrapper);

		if (shipmentsInfoEntity == null) {
			return new BaseDataResDto<LogisticsInfoResData>(Status.ERROR, "根据运单号查询不到物流信息");
		}

		String result = Express100Util.expressQuery(shipmentsInfoEntity.getCompanyCode(), expressNo, null, null, null, 0);

		JSONObject jsonObject = JSONObject.fromObject(result);
		Map<String, Class> classMap = new HashMap<String, Class>();
		classMap.put("data", LogisticsInfo.class);
		LogisticsInfoResData logisticsInfoResData = (LogisticsInfoResData) JSONObject.toBean(jsonObject,
				LogisticsInfoResData.class, classMap);
		if (logisticsInfoResData.getIscheck() == null) {
			// 未揽件默认值为未签收
			logisticsInfoResData.setIscheck(0);
		}
		logisticsInfoResData.setCourierName(shipmentsInfoEntity.getCompanyName());
		List<LogisticsInfo> listMap = logisticsInfoResData.getData();
		LogisticsInfo logisticsInfo = new LogisticsInfo();

		if (listMap == null || listMap.size() == 0) {
			listMap = new ArrayList<>();
		}
		logisticsInfo.setContext("待揽件");
		logisticsInfo.setFtime(TimeUtil.date2String(shipmentsInfoEntity.getSendDate(), null));
		listMap.add(logisticsInfo);

		logisticsInfoResData.setData(listMap);

		BaseDataResDto<LogisticsInfoResData> baseDataResDto = new BaseDataResDto<LogisticsInfoResData>(Status.SUCCESS);
		baseDataResDto.setData(logisticsInfoResData);
		return baseDataResDto;
	}

	@Override
	public BaseDataResDto<ShopingOrderResData> integralExchangeGoods(BaseDataReqDto<IntegralExchangeGoodsReqData> param, String userId) {
		// 获取用户资金
		CapitalMain capitalMain = capitalMainMapper.selectOneByUserId(userId);
		if (capitalMain == null) {
			if(!capitalMainService.createCapitalMain(userId))return new BaseDataResDto<ShopingOrderResData>(Status.PARAMETERERROR, "暂无积分数据");;
		}

        Integer num = param.getData().getNum();
		Goods goods = goodsMapper.selectById(param.getData().getGoodsId());
		if (num > goods.getStockVolume()) return new BaseDataResDto<>(Status.ERROR.setMessage("商品库存不足"));

		//判断积分是否够用
		if(capitalMain.getIntegral() < Arith.multiplys(2, goods.getIntegral() , num) )
		    return new BaseDataResDto<>(Status.ERROR,"积分不足，请攒够积分后再来兑换哦～");

		// 商品加入购物车生成订单信息
		ShopingOrder shopingOrder = orderInfo(param.getData().getGoodsId(), userId,
				param.getData().getAddressId(), param.getData().getRemark(), param.getData().getNum());

		// 组装兑换记录信息
		ExchangeLog exchangeLog = new ExchangeLog();
		exchangeLog.setType(CommonIntValueEnum.EXCHANGELOG_TYPE_SHOPING.getValue());
		exchangeLog.setGoodName(goods.getName());
		exchangeLog.setDiscountCoupon(goods.getUuId());
		exchangeLog.setIntegral(goods.getIntegral());
		exchangeLog.setOrderId(shopingOrder.getUuId());
		exchangeLog.setNum(param.getData().getNum());
		exchangeLog.setDiscountCouponType(CommonIntValueEnum.DISCOUNT_COUPON_TYPE_EXCHANGE.getValue());
		exchangeLog.setUuId(UUID_MD5.getUUID());
		exchangeLog.setUserId(userId);
		exchangeLogMapper.insertOne(exchangeLog);
		
		// 修改资金增加流水
		Boolean bool = capitalMainService.updateCapitalMain(userId, FlowTypeEnum.INTEGRAL,
				(goods.getIntegral() * param.getData().getNum()) + "", FlowTypeEnum.DECREASE, FlowTypeEnum.EXCHANGE_GOODS,
				exchangeLog.getUuId());
		
		if (bool) {
			ShopingOrderResData shopingOrderResData = new ShopingOrderResData();
			BeanUtils.copyProperties(shopingOrder, shopingOrderResData);
            goods.setStockVolume(goods.getStockVolume() - num).setSalesVolume(goods.getSalesVolume() + num);
            if (! goodsService.updateById(goods)) return new BaseDataResDto<>(Status.ERROR.setMessage("修改商品库存和销量失败"));
			return new BaseDataResDto<ShopingOrderResData>(Status.SUCCESS).setData(shopingOrderResData);
		}
		
		return new BaseDataResDto<>(Status.ERROR);
	}

	// 兑换商品生成订单记录和购物车记录
	public ShopingOrder orderInfo(String goodsId, String userId, String shopingAddressId, String remark, Integer num) {
		// 根据商品id获取商品信息
		Goods goods = goodsMapper.selectById(goodsId);

		// 商品加入购物车
		ShopingCart shopingCart = new ShopingCart();
		shopingCart.setUuId(UUID_MD5.getUUID()).setGoodsId(goodsId).setPurchaseQuantity(num)// 购买数量
				.setOriginalPayable(goods.getOriginalPrice()).setPresentPayable(goods.getPresentPrice())
				.setWeightTotal(goods.getWeight()).setDealDate(new Date()).setAddDate(new Date())
				.setUpdateDate(new Date()).setChosen(false)
				.setStatus(CommonIntValueEnum.SHOPPING_CART_STATUS_ALLREADY_PAY.getValue()).setAddAuto(true)
				.setUserId(userId);
		shopingCartMapper.insert(shopingCart);

		// 复制收货地址
        ShopingAddress shopingAddress = shopingAddressService.selectById(shopingAddressId);
        AreaInfo areaInfo = areaInfoService.getAreaInfoById(shopingAddress.getAreaInfoId());
        String areaInfoIdNew = UUID_MD5.getUUID();
        areaInfoService.saveAreaInfo(areaInfo.setUuId(areaInfoIdNew));
        String shopingAddressIdNew = UUID_MD5.getUUID();
        shopingAddressService.insert(shopingAddress.setUuId(shopingAddressIdNew).setAreaInfoId(areaInfoIdNew).setAuto(true));

        // 生成订单信息
		ShopingOrder order = new ShopingOrder();
		order.setUuId(UUID_MD5.getUUID()).setUserId(userId).setOrderNo(UUID_MD5.orderNo()).setDelivery("申通快递")
				.setDeliveryFee(0.0).setWeightTotal(goods.getWeight()).setAmount(0.0).setPayType(4)// 积分兑换
				.setCreateDate(new Date()).setShopingAddressId(shopingAddressId)
				.setStatus(CommonIntValueEnum.SHOPPING_ORDER_STATUS_STAY_SHIPMENTS.getValue())
				.setIntegral(goods.getIntegral() * num).setPrinted(false).setRemindSend(false);
		shopingOrderMapper.insert(order);

		// 保存购物车和订单中间表

		ShopingOrderMiddleShopingCart orderMiddleShopingCart = new ShopingOrderMiddleShopingCart()
				.setUuId(UUID_MD5.getUUID()).setShopingCartId(shopingCart.getUuId()).setOrderId(order.getUuId());
		somscService.insert(orderMiddleShopingCart);

		return order;
	}

	@Override
	public BaseResDto uploudRefundNum(BaseDataReqDto<UploudRefundNumReqData> param) {
		
		EntityWrapper<ShoppingOrderRefundEntity> wrapper = new EntityWrapper<ShoppingOrderRefundEntity>();
		wrapper.eq("order_id", param.getData().getOrderId());
		ShoppingOrderRefundEntity shoppingOrderRefundEntity = shopingOrderRefundService.selectOne(wrapper);
		
		if(shoppingOrderRefundEntity == null) return BaseResDto.baseResDto(Status.ERROR, "参数错误");
		
		shoppingOrderRefundEntity.setRefundNum(param.getData().getRefundNum());
		shopingOrderRefundService.updateById(shoppingOrderRefundEntity);
		
		return new BaseResDto(Status.SUCCESS);
	}

    @Override
    public BaseDataResDto<HashMap> findAndSetOrderAutoSet(HashMap map) {
        if (map.keySet().size() > 0) {
            mongoTemplate.findAndRemove(new Query(), HashMap.class, "order_auto_set");
            mongoTemplate.save(map, "order_auto_set");
        }
        HashMap orderAutoSetMap = mongoTemplate.findOne(new Query(), HashMap.class, "order_auto_set");
        return new BaseDataResDto<HashMap>(Status.SUCCESS).setData(orderAutoSetMap);
    }

}
